//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <core.h>

//
// KMutex
//
bool_t KMutex::IsHeld() const
{
    return (m_pOwner == GetCurrentThread());
}

void KMutex::Lock()
{
#ifdef DEBUG_KMUTEX
    if (!PreemptionEnabled()) {
        kprintf("KMutex define file and line is %s, %d\n", m_pFilepath, m_nLine);
        DebugBreak();
    }
#else
    assert(PreemptionEnabled());
#endif //DEBUG_KMUTEX
    GetCurrentThread()->m_activeLock._Lock();

    _Lock();
}

void KMutex::Unlock()
{
    _Unlock();

    GetCurrentThread()->m_activeLock._Unlock();
}

void KMutex::_Lock()
{
    register Thread *pCurrentThread = GetCurrentThread();

    m_waitListLock.Lock();
    if (NULL == InterlockedCompareExchangePointer(
            (void **)&m_pOwner, pCurrentThread, NULL)) {
        m_pOwner->AddOwnedSyncObject(this);
    }
    else if (m_pOwner != GetCurrentThread()) {
        while (NULL != InterlockedCompareExchangePointer(
                (void **)&m_pOwner, pCurrentThread, NULL)) {
            WaiterReadyToUninterruptibleSleep();
            m_waitListLock.Unlock();

            Schedule();

            m_waitListLock.Lock();
        }
        m_pOwner->AddOwnedSyncObject(this);
    }
    m_waitListLock.Unlock();

    m_uNested++;
}

void KMutex::_Unlock()
{
    assert(m_pOwner == GetCurrentThread());

    m_uNested--;
    if (0 == m_uNested) {
        bool_t bOriginalPreemption = DzDisablePreemption();
        ClearOwner();
        DzRestorePreemption(bOriginalPreemption);
        WakeUpSomeWaiters(TRUE);
    }
}
